package cn.sunflower.common.jwt;

import cn.sunflower.common.jwt.enums.TokenEnum;
import cn.sunflower.common.jwt.request.TokenGenerationRequest;
import cn.sunflower.common.jwt.util.*;
import com.auth0.jwt.JWT;
import com.auth0.jwt.JWTVerifier;
import com.auth0.jwt.algorithms.Algorithm;
import com.auth0.jwt.impl.PublicClaims;
import com.auth0.jwt.interfaces.DecodedJWT;
import com.jsoniter.JsonIterator;
import com.jsoniter.any.Any;
import org.apache.commons.codec.binary.Base64;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.env.Environment;

import java.io.UnsupportedEncodingException;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;

/**
 * JWT操作工具类
 *
 */
public class JWTUtil {
    @Autowired
    private Environment env;

    private static Logger logger = LoggerFactory.getLogger(JWTUtil.class);

    /**
     * 实际调用的生成方法
     * @return
     */
    public  String doGenerateJWT(TokenGenerationRequest request){
        UserDefinedPayload userDefinedPayload = ModelMapperUtil.get().map(request, UserDefinedPayload.class);
        JWTPayload payload = generateJwtPayload(userDefinedPayload, request.getSource());

        try {
            String token = JWTUtil.generateJWT(new JWTHeader(), payload, env.getProperty("jwt.secret"));
            logger.info("生成Token成功");
            return token;
        } catch (UnsupportedEncodingException e) {
            logger.warn(ExceptionUtil.getStackTraceAsString(e));
            logger.info("服务器异常");
            return null;
        }
    }
    private  JWTPayload generateJwtPayload(UserDefinedPayload userDefinedPayload, TokenEnum.TokenSource source) {
        JWTPayload payload = new JWTPayload();
        payload.setIss(env.getProperty("jwt.payload.iss"));
        payload.setIat(new Date());

        if (source == TokenEnum.TokenSource.ADMIN) {
            payload.setExp(DateTimeUtil.getThreeOclockAMOfTheNextDay());  //过期时间为第二天的凌晨三点钟
        } else if (source == TokenEnum.TokenSource.END_USER) {
            payload.setExp(DateTimeUtil.getThreeOclockAMOfSeventhDay());  //过期时间为第七天的凌晨三点钟
        }

        payload.setJti(UUIDUtil.randomUUID());
        payload.setUserId(userDefinedPayload.getUserId());
        payload.setLoginName(userDefinedPayload.getLoginName());
        payload.setHeadPortrait(userDefinedPayload.getHeadPortrait());
        payload.setRoleIdList(userDefinedPayload.getRoleIdList());
        payload.setTenantId(userDefinedPayload.getTenantId());

        payload.setJobNum(userDefinedPayload.getJobNum());
        payload.setPhone(userDefinedPayload.getPhone());
        return payload;
    }

    /**
     * 实际调用的校验方法
     * @param token
     * @throws UnsupportedEncodingException
     */
    public void doVerifyToken(String token) throws UnsupportedEncodingException {
        JWTUtil.verifyToken(token, env.getProperty("jwt.secret"));
    }
    /**
     * 生成JWT
     *
     * @param header  头
     * @param payload 载荷
     * @param secret  密码
     * @return JWT字符串
     * @throws UnsupportedEncodingException 不支持的编码异常
     */
    public static String generateJWT(JWTHeader header, JWTPayload payload, String secret) throws UnsupportedEncodingException {

        Algorithm algorithm = Algorithm.HMAC256(secret);

        Map<String, Object> headerMap = new HashMap<>();
        headerMap.put(PublicClaims.ALGORITHM, header.getAlg());
        headerMap.put(PublicClaims.TYPE, header.getTyp());

        return JWT.create()
                .withHeader(headerMap)
                .withIssuer(payload.getIss())
                .withIssuedAt(payload.getIat())
                .withExpiresAt(payload.getExp())
                .withNotBefore(payload.getNbf())
                .withJWTId(payload.getJti())
                .withAudience(payload.getAud())
                .withSubject(payload.getSub())
                .withClaim("userId", payload.getUserId())
                .withClaim("loginName", payload.getLoginName())
                .withClaim("headPortrait", payload.getHeadPortrait())
                .withClaim("tenantId", payload.getTenantId())
                .withClaim("tenantType", payload.getTenantType())
                .withClaim("realName",payload.getRealName())
                .withClaim("identityType",payload.getRealName())
                .withArrayClaim("roleIdList", payload.getRoleIdList())
                .sign(algorithm);
    }

    /**
     * 校验JWT
     *
     * @param token  JWT
     * @param secret 密钥
     * @return DecodedJWT
     * @throws UnsupportedEncodingException 不支持的编码异常
     */
    public static DecodedJWT verifyToken(String token, String secret) throws UnsupportedEncodingException {
        Algorithm algorithm = Algorithm.HMAC256(secret);
        JWTVerifier jwtVerifier = JWT.require(algorithm).build();
        return jwtVerifier.verify(token);
    }

    /**
     * 根据token解析出Payload数据
     *
     * @param token token
     * @return Payload
     */
    public static String getPayloadStringByToken(String token) {
        String[] split = token.split("\\.");
        String payLoadString = split[1];
        byte[] bytes = Base64.decodeBase64(payLoadString);
        try {
            return new String(bytes, "UTF-8");
        } catch (UnsupportedEncodingException e) {
            logger.error(ExceptionUtil.getStackTraceAsString(e));
            return "";
        }
    }

    /**
     * 根据token解析出Payload数据
     *
     * @param token Token
     * @return Payload
     */
    public static String getPayloadStringByToken(String token, String secret) {
        String payloadString = "";
        DecodedJWT decodedJWT;
        try {
            decodedJWT = JWTUtil.verifyToken(token, secret);
        } catch (UnsupportedEncodingException e) {
            logger.error(ExceptionUtil.getStackTraceAsString(e));
            return payloadString;
        }

        String payloadBase64 = decodedJWT.getPayload();
        byte[] decodeBase64 = EncodeUtil.decodeBase64(payloadBase64);
        try {
            payloadString = new String(decodeBase64, "UTF-8");
        } catch (UnsupportedEncodingException e) {
            logger.error(ExceptionUtil.getStackTraceAsString(e));
        }

        // TODO:转化为Payload对象
//        Any any = JsonIterator.deserialize(payloadString);
//        JWTPayload payload = new JWTPayload();
//        payload.setIss(any.get("iss").toString());

        return payloadString;
    }

    /**
     * 通过Token获取UserID
     *
     * @param token token
     * @return userId
     */
    public static String getUserIdByToken(String token) {
        String payload = JWTUtil.getPayloadStringByToken(token);
        return JsonIterator.deserialize(payload).get("userId").toString();
    }

    /**
     * 通过Token获取loginName
     *
     * @param token token
     * @return loginName
     */
    public static String getLoginNameByToken(String token) {
        if (StringUtils.isEmpty(token)) {
            return "无用户token";
        }
        String payload = JWTUtil.getPayloadStringByToken(token);
        return JsonIterator.deserialize(payload).get("loginName").toString();
    }

    /**
     * 通过Token获取TenantId
     *
     * @param token token
     * @return userId
     */
    public static String getTenantIdByToken(String token) {
        if (StringUtils.isEmpty(token)) {
            return "无用户token";
        }
        String payload = JWTUtil.getPayloadStringByToken(token);
        return JsonIterator.deserialize(payload).get("tenantId").toString();
    }

    /**
     * 通过Token获取TenantType
     *
     * @param token token
     * @return userId
     */
    public static String getTenantTypeByToken(String token) {
        if (StringUtils.isEmpty(token)) {
            return "无用户token";
        }
        String payload = JWTUtil.getPayloadStringByToken(token);
        return JsonIterator.deserialize(payload).get("tenantType").toString();
    }

    /**
     * 通过Token获取HeadPortrait
     *
     * @param token token
     * @return userId
     */
    public static String getHeadPortraitByToken(String token) {
        if (StringUtils.isEmpty(token)) {
            return "无用户token";
        }
        String payload = JWTUtil.getPayloadStringByToken(token);
        return JsonIterator.deserialize(payload).get("headPortrait").toString();
    }

    /**
     * 通过Token获取 realName
     *
     * @param token token
     * @return realName
     */
    public static String getRealNameByToken(String token) {
        if (StringUtils.isEmpty(token)) {
            return "无用户token";
        }
        String payload = JWTUtil.getPayloadStringByToken(token);
        return JsonIterator.deserialize(payload).get("realName").toString();
    }

    /**
     * 通过Token获取 identityType
     *
     * @param token token
     * @return realName
     */
    public static String getIdentityTypeByToken(String token) {
        String payload = JWTUtil.getPayloadStringByToken(token);
        return JsonIterator.deserialize(payload).get("identityType").toString();
    }

    /**
     * 通过Token获取UserDefinedPayload
     *
     * @param token token
     * @return userId
     */
    public static UserDefinedPayload getUserDefinedByToken(String token) {
        if (StringUtils.isEmpty(token)) {
            return null;
        }
        String payload = JWTUtil.getPayloadStringByToken(token);
        Any any = JsonIterator.deserialize(payload);
        return new UserDefinedPayload(any.get("userId").toString(), any.get("loginName").toString(), any.get("headPortrait").toString(),
                any.get("tenantId").toString(), any.get("tenantType").toString(), any.get("realName").toString(), any.get("identityType").toString());
    }
}
